package state

import (
	"osiris/dto"
	"osiris/errors"
	"osiris/logger"
)

// TxStatus 交易状态
type TxStatus int

// const 交易状态
//
//	@param TxInvalid 不合法
//	@param TxQueued 需进入交易池的queued
//	@param Peding 需进入交易池的pending
const (
	TxInvalid TxStatus = iota + 1
	TxQueued
	TxPending
)

// TxHandler 交易处理接口，不同的交易具体实现不同的处理逻辑
type TxHandler interface {

	// Verify 验证交易内容（不包含密码学验证）
	//  @param tries 状态树
	//  @return bool 验证是否通过
	Verify(tries ...interface{}) bool

	// Commit 将交易提交至状态树
	//  @param tries 状态树
	//  @return bool 是否执行成功
	Commit(tries ...interface{}) bool

	// Undo 将交易从状态树回滚
	//  @param trie 状态树
	//  @return bool 是否执行成功
	Undo(trie ...interface{}) bool
}

type StateKeyValue struct {
	Key  []byte
	Leaf dto.StateLeaf
}

// AccountCommitRoutine 提交账户状态变更的原子协程
type AccountCommitRoutine struct {
	Kvs     []StateKeyValue
	Trie    *AccountStateTrie
	oleTrie *AccountStateTrie
}

func (routine *AccountCommitRoutine) OnAtomicPrepare() error {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [AccountCommitRoutine.OnAtomicPrepare()]": "account trie is nil"})
		return &errors.UnknownAccountTrieError{}
	}

	routine.Trie.Lock()
	tempTrieVar := *routine.Trie
	routine.oleTrie = &tempTrieVar

	return nil
}

func (routine *AccountCommitRoutine) Commit() error {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [AccountCommitRoutine.Commit()]": "account trie is nil"})
		return &errors.UnknownAccountTrieError{}
	}

	if len(routine.Kvs) == 0 {
		return nil
	}
	
	for i := 0; i < len(routine.Kvs); i++ {
		err := routine.Trie.commitState(routine.Kvs[i].Key, routine.Kvs[i].Leaf, true)
		if err != nil {
			return err
		}
	}

	return nil
}

func (task *AccountCommitRoutine) Rollback() {
	task.Trie = task.oleTrie
}

func (routine *AccountCommitRoutine) OnAtomicEnd() {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [AccountCommitRoutine.OnAtomicEnd()]": "account trie is nil"})
		return
	}

	routine.Trie.UnLock()
}

// PeerCommitRoutine 提交节点状态变更的原子协程
type PeerCommitRoutine struct {
	Kvs     []StateKeyValue
	Trie    *PeerStateTrie
	oleTrie *PeerStateTrie
}

func (routine *PeerCommitRoutine) OnAtomicPrepare() error {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [PeerCommitRoutine.OnAtomicPrepare()]": "peer trie is nil"})
		return &errors.UnknownPeerTrieError{}
	}

	routine.Trie.Lock()
	tempTrieVar := *routine.Trie
	routine.oleTrie = &tempTrieVar

	return nil
}

func (routine *PeerCommitRoutine) Commit() error {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [PeerCommitRoutine.Commit()]": "peer trie is nil"})
		return &errors.UnknownPeerTrieError{}
	}

	if len(routine.Kvs) == 0 {
		return nil
	}
	for i := 0; i < len(routine.Kvs); i++ {
		err := routine.Trie.commitState(routine.Kvs[i].Key, routine.Kvs[i].Leaf, false)
		if err != nil {
			return err
		}
	}

	return nil
}

func (task *PeerCommitRoutine) Rollback() {
	task.Trie = task.oleTrie
}

func (routine *PeerCommitRoutine) OnAtomicEnd() {
	if routine.Trie == nil {
		logger.Error(map[string]interface{}{"[state] [PeerCommitRoutine.OnAtomicEnd()]": "peer trie is nil"})
		return
	}

	routine.Trie.UnLock()
}
